/*
    DIMVisual, the Data Integration Model for Visualization of trace files.
    Copyright (c) 2008 Lucas Mello Schnorr <schnorr@gmail.com>

    This file is part of DIMVisual.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "Integrator.h"

@implementation Integrator
- (id) init
{
	self = [super init];
	containers = [[NSMutableDictionary alloc] init];
	ordering = [[Order alloc] init];
	//hierarchy must be defined later
	return self;
}

- (void) dealloc
{
	[containers release];
	[ordering release];
	[super dealloc];
}

- (NSString *) identifierForEntity: (NSArray *) names ids: (NSArray *) ids
{
        NSMutableString *ret;
        int i;

        if (names == nil || ids == nil || [names count] != [ids count]){
                NSLog (@"Integrator: names, ids must be not equal and have"
                                "the same size");
                return nil;
        }

        if ([[names objectAtIndex: 0] isEqual: @"0"]){
                return [NSString stringWithString: @"0"];
        }

        ret = [[NSMutableString alloc] init];
        for (i = 0; i < [names count]; i++){
                [ret appendFormat: @"%@_%@", [names objectAtIndex: i],
                        [ids objectAtIndex: i]];
                if ([names count] > i+1){
                        [ret appendFormat: @"-"];
                }
        }

        [ret autorelease];
        return ret;
}

- (PajeCreateContainer *) createContainerWithName: (NSString *) name
        alias: (NSString *) alias container: (NSString *) container
        type: (NSString *) type time: (NSString *) time
{
        PajeCreateContainer *cret = [[PajeCreateContainer alloc]
                       initWithTime: time];
        [cret setContainer: container];
        [cret setName: name];
// - this generates a huge problem when there are
//      the same thread id in two machines, for example
//      [cret setName: alias];  
        [cret setAlias: alias];
        [cret setType: type];
        [cret autorelease];
        return cret;
}


- (NSArray *) createContainerForEntity: (NSArray *) names ids: (NSArray *) ids
        time: (NSString *) time
{
        NSMutableArray *ret, *hdefined;
        //NSMutableSet *xxx;
        ret = [[NSMutableArray alloc] init];

        hdefined = [hierarchy entityOfType: @"container"];

        if (names == nil || ids == nil || time == nil || [names count] != [ids count]){
                [ret autorelease];
                return ret;
        }

        if ([[containers objectForKey: @"0"] count] == 0){
                [ret addObject: [self createContainerWithName: @"XXX"
                                        alias: @"roote" container: @"0"
                                        type: @"0" time: time]];
                [[containers objectForKey: @"0"] addObject: @"0"];
        }

        int i;
        for (i = 0; i < [names count]; i++){
                NSString *ide;
                int j;
                NSMutableArray *nameide, *idide;
                nameide = [[NSMutableArray alloc] init];
                idide = [[NSMutableArray alloc] init];
                for (j = 0; j < i+1 && j < [names count]; j++){
                        [nameide addObject: [names objectAtIndex: j]];
                        [idide addObject: [ids objectAtIndex: j]];
                }
                ide = [self identifierForEntity: nameide ids: idide];
                [ide retain];
                if ([[containers objectForKey: [names objectAtIndex: i]] containsObject: ide] == NO){
                        NSMutableArray *cname, *cid;
                        NSString *container;
                        cname = [[NSMutableArray alloc] initWithArray: nameide];
                        [cname removeLastObject];
                        cid = [[NSMutableArray alloc] initWithArray: idide];
                        [cid removeLastObject];
                        if ([cname count] == 0){
                                container = @"0";
                        }else{
                                container = [self identifierForEntity: cname ids: cid];
                        }
                        [ret addObject:
                                [self createContainerWithName: [idide componentsJoinedByString: @"-"]// lastObject]
                                        alias: ide
                                        container: container
                                        type: [self aliasToName: [nameide lastObject]]
                                        time: time]];
                        [[containers objectForKey: [names objectAtIndex: i]] addObject: ide];
                        [cname release];
                        [cid release];
                }
                [ide release];
                [idide release];
                [nameide release];
        }
        [ret autorelease];
        return ret;
}

- (NSString *) newAliasToName: (NSString *) nameP
{
        return [hierarchy newAliasToName: nameP];
}

- (NSString *) aliasToName: (NSString *) nameP
{
        return [hierarchy aliasToName: nameP];
}

- (NSArray *) entitiesExists: (NSArray *) names
{
        int i;
        NSMutableArray *ret;
        ret = [NSMutableArray array];
        if (names == nil) return nil;
        for (i = 0; i < [names count]; i++){
                if ([self aliasToName: [names objectAtIndex: i]] == nil){
                        [ret addObject: [names objectAtIndex: i]];
                }
        }
        return ret;
}

- (PajeHierarchy *) hierarchy
{
        return hierarchy;
}

- (NSDictionary *) mergeHierarchies: (NSArray *) hierarchies
{
	unsigned int i;
	if ([hierarchies count] == 0){
		return nil;
	}else if ([hierarchies count] == 1){
		return [hierarchies objectAtIndex: 0];
	}

	/* check for mandatory type=root */
	for (i = 0; i < [hierarchies count]; i++){
		NSDictionary *conf = [hierarchies objectAtIndex: i];
		if ([conf objectForKey: @"root"] == nil){
			NSLog (@"%@ Error: the hierarchy configuration '%@' does not have a mandatory 'root' key.", self, conf);
			return nil;
		}
	}

	/* */
	NSMutableDictionary *ret = [[NSMutableDictionary alloc] init];
	[ret addEntriesFromDictionary: [hierarchies objectAtIndex: 0]];

	/* TODO: automatically merge here */
	//for (i = 1; i < [hierarchies count]; i++){
	//	NSDictionary *conf = [hierarchies objectAtIndex: i];
	//}
	[ret autorelease];
	return ret;
}
@end
